package com.bjsxt.controller.system;


import cn.hutool.core.date.DateUtil;
import com.bjsxt.aspectj.annotation.Log;
import com.bjsxt.aspectj.enums.BusinessType;
import com.bjsxt.constants.Constants;
import com.bjsxt.constants.HttpStatus;
import com.bjsxt.domain.LoginInfo;
import com.bjsxt.domain.Menu;
import com.bjsxt.domain.SimpleUser;
import com.bjsxt.dto.LoginBodyDto;
import com.bjsxt.service.LoginInfoService;
import com.bjsxt.service.MenuService;
import com.bjsxt.utils.AddressUtils;
import com.bjsxt.utils.IpUtils;
import com.bjsxt.utils.ShiroSecurityUtils;
import com.bjsxt.vo.ActiveUser;
import com.bjsxt.vo.AjaxResult;
import com.bjsxt.vo.MenuTreeVo;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.log4j.Log4j2;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.tomcat.util.bcel.Const;
import org.apache.zookeeper.Login;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.security.Security;
import java.util.ArrayList;
import java.util.List;

/**
 * @author:liao
 * @Description:TODO 登录
 * @date:2020/11/20
 */
@RestController
@Log4j2
public class LoginController {

    @Autowired
    private MenuService menuService;

    @Autowired
    private LoginInfoService loginInfoService;
    //登录
    @RequestMapping("login/doLogin")
    //当被@Validated注解标注的类 中有字段标注为@NotNull并且数据为空时
    //会抛出一个MethodArgumentNotValidException异常 此时我们需要全局异常处理
    public AjaxResult login(@RequestBody @Validated LoginBodyDto loginBodyDto, HttpServletRequest request){
        AjaxResult ajaxResult = AjaxResult.success();
        //获取登录用户名
        String username = loginBodyDto.getUsername();
        //获取密码
        String password = loginBodyDto.getPassword();
        //构造用户名和密码的token
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        //获取主体<主体中会保存登录用户的各种信息>
        Subject subject = SecurityUtils.getSubject();
        // 封装登录日志对象LoginInfo
        LoginInfo loginInfo = createLoginInfo(request);
        // 设置登录账户
        loginInfo.setLoginAccount(loginBodyDto.getUsername());
        try {
            //登录
            subject.login(token);
            //得到会话的token也就是redis中存的
            Serializable webToken = subject.getSession().getId();
            ajaxResult.put(Constants.TOKEN,webToken);

            // 说明登录成功
            loginInfo.setMsg("登录成功");
            loginInfo.setLoginStatus(Constants.LOGIN_SUCCESS);
            // 设置登录用户名
            loginInfo.setUserName(ShiroSecurityUtils.getCurrentUserName());
        } catch (AuthenticationException e) {
            log.error("用户名或密码不正确",e);
            ajaxResult = AjaxResult.error(HttpStatus.ERROR,"用户名或密码不正确");
            loginInfo.setMsg("用户名或密码不正确");
            loginInfo.setLoginStatus(Constants.LOGIN_ERROR);
        }
        loginInfoService.insertLoginInfo(loginInfo);
        return ajaxResult;
    }

    /**
     * 构造日志信息对象LoginInfo
     * @param request
     * @return
     */
    private LoginInfo createLoginInfo(HttpServletRequest request) {
        LoginInfo loginInfo = new LoginInfo();
        // 获取用户设备标识对象
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
        // 获取IP地址
        String ipAddr = IpUtils.getIpAddr(request);
        // 获取操作系统
        String os = userAgent.getOperatingSystem().getName();
        // 获取浏览器类型
        String browser = userAgent.getBrowser().getName();
        // 获取登录地址
        String location = AddressUtils.getRealAddressByIP(ipAddr);

        loginInfo.setIpAddr(ipAddr);
        loginInfo.setLoginLocation(location);
        loginInfo.setOs(os);
        loginInfo.setBrowser(browser);
        loginInfo.setLoginTime(DateUtil.date());
        loginInfo.setLoginType(Constants.LOGIN_TYPE_SYSTEM);
        return loginInfo;

    }

    /**
     * 获取用户信息
     */
    @GetMapping("login/getInfo")
    public AjaxResult getInfo(){
        //获取主体
        Subject subject = SecurityUtils.getSubject();
        //获取用户信息
        ActiveUser activeUser = (ActiveUser) subject.getPrincipal();
        //封装返回类
        AjaxResult ajaxResult = AjaxResult.success();
        ajaxResult.put("username",activeUser.getUser().getUserName());
        ajaxResult.put("picture",activeUser.getUser().getPicture());
        ajaxResult.put("roles",activeUser.getRoles());
        ajaxResult.put("permissions",activeUser.getPermissions());
        return ajaxResult;
    }

    /**
     *用户退出
     */
    @GetMapping("login/logout")
    @Log(title = "用户退出",businessType = BusinessType.OTHER)
    public AjaxResult logout(){
        //获取主体
        Subject subject = SecurityUtils.getSubject();
        //退出登录
        subject.logout();
        return AjaxResult.success("用户退出成功!");
    }

    /**
     * 获取菜单信息
     */
    @GetMapping("login/getMenus")
    public AjaxResult getMenus(){
        //获取主体
        Subject subject = SecurityUtils.getSubject();
        //获取用户信息
        ActiveUser activeUser = (ActiveUser) subject.getPrincipal();
        //判断用户是否为超级管理员
        boolean isAdmin = activeUser.getUser().getStatus().equals(Constants.USER_ADMIN);
        SimpleUser simpleUser = null;
        if (!isAdmin){
            simpleUser = new SimpleUser(
              activeUser.getUser().getUserId(),
              activeUser.getUser().getUserName()
            );
        }
        //查询菜单信息
        List<Menu> menuList = menuService.selectMenuTree(isAdmin,simpleUser);
        List<MenuTreeVo> menuTreeVoList  = new ArrayList<>();
        //组装菜单对象
        for (Menu menu : menuList) {
            menuTreeVoList.add(new MenuTreeVo(menu.getMenuId().toString(),menu.getPath()));
        }
        return AjaxResult.success(menuTreeVoList);
    }
}
